//@author A0096759E

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Stack;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import logic.CommandDecoder;
import storage.Storage;
import applogger.AppLogger;


public class LifeShelfCommandLine {

	private JFrame frmLifeshelf;
	private JTextField textField;
	private JTextArea textPane;
	private Storage eventsList;
	private CommandDecoder commandDecoder;
	private Stack<String> prevCommands;
	private Stack<String> nextCommands;

	private static final String LIFESHELF_WELCOME_MESSAGE = "Welcome To LifeShelf!\nTell me what to do, or type \"help\" to see what you can do!\n";
	protected static final String LIFESHELF_COMMAND_LINE = "[Command]: %s";
	protected static final String LIFESHELF_SEPARATOR_LINE = "--------------------------------------------------";
	private static final String LIFESHELF_ENTER_COMMAND_PROMPT = "Enter Your Command Here:";
	
	private static final String STRING_NEW_LINE = "\n";
	private static final String STRING_EMPTY = "";
	
	private static final String UI_TITLE_LIFESHELF = "LifeShelf";
	private static final String UI_FONT_SEGOE_UI_SEMIBOLD = "Segoe UI Semibold";
	private static final String UI_FONT_SEGOE_UI = "Segoe UI";
	private static final String JAVA_VM_NAME = "java.vm.name";
	private static final CharSequence JAVA_VM_NAME_KEYWORD_64_BIT = "64-Bit";
	private static final String RESOURCE_PATH_SWT_X64_JAR = "/references/swt_64bit.jar";
	private static final String RESOURCE_PATH_SWT_X86_JAR = "/references/swt_32bit.jar";
	private static final Object ERROR_DIALOG_MESSAGE = "error dialog message";
	private static final String ERROR_DIALOG_TITLE = "error dialog title";
	
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		AppLogger.clear();
		loadSwtLibrary();
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					LifeShelfCommandLine window = new LifeShelfCommandLine();
					//Set Window Location
					Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
					int width = (int)screenSize.getWidth();
					int height = (int)screenSize.getHeight();
					window.frmLifeshelf.setLocation(width-800,height-700);
					
					window.frmLifeshelf.setVisible(true);
					window.write(LIFESHELF_WELCOME_MESSAGE+LIFESHELF_SEPARATOR_LINE);


				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	/**
	 * Loads the correct SWT Version before starting anything.
	 */
	private static void loadSwtLibrary() {
		AppLogger.log("loading the correct SWT version");
		AppLogger.log("Deciding which version of the SWT (32- or 64-bit) library to include.");
		
		URL pathToSWT;
		if(System.getProperty(JAVA_VM_NAME).contains(JAVA_VM_NAME_KEYWORD_64_BIT)) {
			pathToSWT = LifeShelfCommandLine.class.getResource(RESOURCE_PATH_SWT_X64_JAR);
		}
		else {
			pathToSWT = LifeShelfCommandLine.class.getResource(RESOURCE_PATH_SWT_X86_JAR);
		}
		
		if (pathToSWT != null) {
			AppLogger.log("Path to SWT library found.");
		} else {
			AppLogger.log("Path to SWT library not found.");
			AppLogger.log("Terminating...");
			System.exit(1);
		}
	
		try {
			AppLogger.log("Reflecting the URLClassLoader.addURL method to expose it (protected -> public)");
			Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
			method.setAccessible(true);
	
			method.invoke((URLClassLoader)LifeShelfCommandLine.class.getClassLoader(), pathToSWT);
			AppLogger.log("Invoked the URLClassLoader.addURL method of the ATypistCalendar class'es ClassLoader.");
		} catch (Exception e) {
			AppLogger.log("Unable to load the SWT library! Displaying error message and exiting.");
			e.printStackTrace();
			JOptionPane.showMessageDialog(new JDialog(), ERROR_DIALOG_MESSAGE, ERROR_DIALOG_TITLE, JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		AppLogger.log("SWT library loaded successfully.");
	}
	

	/**
	 * Create the application.
	 */
	public LifeShelfCommandLine() {
		eventsList = new Storage();
		commandDecoder = new CommandDecoder(eventsList); 
		prevCommands = new Stack<String>();
		nextCommands = new Stack<String>();
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmLifeshelf = new JFrame();
		frmLifeshelf.setTitle(UI_TITLE_LIFESHELF);
		frmLifeshelf.setResizable(false);
		frmLifeshelf.getContentPane().setBackground(Color.DARK_GRAY);
		frmLifeshelf.getContentPane().setLayout(null);
		
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(10, 11, 694, 528);
		frmLifeshelf.getContentPane().add(scrollPane);
		
		textPane = new JTextArea();
		textPane.setLineWrap(true);
		textPane.setFont(new Font(UI_FONT_SEGOE_UI_SEMIBOLD, Font.PLAIN, 14));
		textPane.setEditable(false);
		textPane.setWrapStyleWord(true);
		scrollPane.setViewportView(textPane);
		
		JLabel lblEnterYourCommand = new JLabel(LIFESHELF_ENTER_COMMAND_PROMPT);
		lblEnterYourCommand.setForeground(Color.WHITE);
		lblEnterYourCommand.setFont(new Font(UI_FONT_SEGOE_UI, Font.BOLD, 14));
		lblEnterYourCommand.setBounds(10, 550, 184, 20);
		frmLifeshelf.getContentPane().add(lblEnterYourCommand);
		
		textField = new JTextField();
		textField.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    try {
                        String command = textField.getText();
                        if (command.equals(STRING_EMPTY)) return;
                        
                        
                        this.refreshStacks();
                        prevCommands.push(command);
                        
                        textField.setText(STRING_EMPTY);
                        textField.setEditable(false);
                        
                        //TODO Processing
                        write(STRING_EMPTY);
                        write(String.format(LIFESHELF_COMMAND_LINE, command));
                        write(commandDecoder.decodeUserInput(command));
                        write(LIFESHELF_SEPARATOR_LINE);
                        
                        textField.setEditable(true);

                    } catch (Exception ex) {}
                } else if (e.getKeyCode() == KeyEvent.VK_UP) {
                	//TODO allow for previous commands to come back up
                	if (!prevCommands.isEmpty()) {
                		textField.setText(prevCommands.peek());
                		if (prevCommands.size() > 1) {
                			nextCommands.push(prevCommands.pop());
                		}
                	}
                } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                	//TODO allow for previous commands to come back up
                	if (!nextCommands.isEmpty()) {
                		prevCommands.push(nextCommands.pop());
                		textField.setText(prevCommands.peek());
                	} else {
                		textField.setText(STRING_EMPTY);
                	}
                }

			}

			private void refreshStacks() {
				// TODO Auto-generated method stub
				while (!nextCommands.isEmpty()) {
					prevCommands.push(nextCommands.pop());
				}
				
			}
		});
		textField.setFont(new Font(UI_FONT_SEGOE_UI, Font.PLAIN, 14));
		textField.setBounds(10, 571, 694, 30);
		frmLifeshelf.getContentPane().add(textField);
		textField.setColumns(10);
		frmLifeshelf.setBounds(100, 100, 720, 640);
		frmLifeshelf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	/**
	 * Writes a string to the UI Text Area.
	 * @param lines
	 */
	public void write(String... lines) {
        try {
            textPane.getDocument().insertString(textPane.getDocument().getLength(), STRING_EMPTY, null);
            for (String line : lines) {
                textPane.getDocument().insertString(textPane.getDocument().getLength(), line, null);
            }
            textPane.getDocument().insertString(textPane.getDocument().getLength(), STRING_NEW_LINE, null);
            textPane.setCaretPosition(textPane.getDocument().getLength());
        }
        catch (Exception e) {}
    }
}
